/*
 * @(#)MainActionServlet.java
 *
 * Copyright (c) 2003 DCIVision Ltd
 * All rights reserved.
 *
 * This software is the confidential and proprietary information of DCIVision
 * Ltd ("Confidential Information").  You shall not disclose such Confidential
 * Information and shall use it only in accordance with the terms of the license
 * agreement you entered into with DCIVision Ltd.
 */
package com.dcivision.framework.web;

import java.sql.Connection;
import java.text.ParseException;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.StringTokenizer;

import javax.servlet.ServletException;

import org.apache.struts.action.ActionServlet;
import org.apache.struts.config.ModuleConfig;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.quartz.CronTrigger;
import org.quartz.JobDataMap;
import org.quartz.JobDetail;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.JobListener;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.impl.StdSchedulerFactory;

import com.dcivision.dms.core.DmsDocumentClearCache;
import com.dcivision.dms.core.DmsProfileJob;
import com.dcivision.framework.ApplicationContainer;
import com.dcivision.framework.DataSourceFactory;
import com.dcivision.framework.DynamicClassLoader;
import com.dcivision.framework.EventLogger;
import com.dcivision.framework.GlobalConstant;
import com.dcivision.framework.MessageResourcesFactory;
import com.dcivision.framework.SessionContainer;
import com.dcivision.framework.SystemParameterConstant;
import com.dcivision.framework.SystemParameterFactory;
import com.dcivision.framework.TextUtility;
import com.dcivision.framework.UserInfoFactory;
import com.dcivision.framework.Utility;
import com.dcivision.framework.bean.EventMessageCode;
import com.dcivision.framework.dao.AuditLoginOutDAObject;
import com.dcivision.framework.dao.EventMessageCodeDAObject;
import com.dcivision.framework.dao.GlobalReferenceDAObject;
import com.dcivision.framework.dao.SysFunctionDAObject;
import com.dcivision.lucene.IndexAutoTrigger;
import com.dcivision.mail.core.EmailSolutionHandler;
import com.dcivision.workflow.core.AutomaticTaskHandler;


/**
 * MainActionServlet.java
 * 
 * This class instead of ActionServlet of Struts, the goal of this class is to do some init process that defined in
 * com.dcivision.framework.MainRequestProcessor.init()
 * 
 * @author Charlie.liu
 * @company DCIVision Limited
 * @creation date 26/06/2005
 * @version $Revision: 1.21.2.2 $
 * 
 */
public class MainActionServlet extends ActionServlet {

  private static final Log logger= LogFactory.getLog(ActionServlet.class);

	/**
	 * init
	 * 
   * @throws ServletException Servlet exception
	 */

	public void init() throws ServletException {
    logger.info("MainActionServlet.init() start");
		super.init();
    logger.info("MainActionServlet.init() finished");

    // Create a new ApplicationContainer instance
    ApplicationContainer applicationContainer = new ApplicationContainer();

    // Initialize Dynamic Class Loader.
    DynamicClassLoader classLoader = new DynamicClassLoader();
    getServletContext().setAttribute(GlobalConstant.CLASS_LOADER_KEY, classLoader);

		// Initialize Datasource.
    this.initDataSource();

    // Initialize Message Resources.
    this.initMessageResources();

		// Initialize Global Reference.
		this.initGlobalReference();

    // Initialize System Function and store the cache into ApplicationContainer
    this.initSysFunction(applicationContainer);

    // Initialize Scheduler.
    this.initScheduler();

    // Initialize document retention period file archiving job
    this.initDmsProfileJob();

    // clear cache file in system cache folder / lee 06/12/13 EIP-1182
    this.initClearCacheFileJob();

    // initialize Full Text Factory.
    this.startFullTextIndexFactory();

    // start email archive tracker
    this.startEmailArchiveTracker();

    // load event logger event code
    this.loadEventCode();

		// reset Login Log
    this.resetLoginLog();
		
    // store Application Container into application scope
    getServletContext().setAttribute(GlobalConstant.APPLICATION_CONTAINER_KEY, applicationContainer);
  }

  public void destroy() {
    try {
      com.dcivision.framework.SchedulerFactory.getScheduler().shutdown();
    } catch (SchedulerException e) {
      logger.error("Error Shutdown Scheduler", e);
    }
    super.destroy();
  }

  /**
   * startFullTextIndexFactory
   * 
   * @throws javax.servlet.ServletException
     */
  protected void initDataSource() throws javax.servlet.ServletException {
    logger.info("MainActionServlet.initDataSource() start");
    try {
      DataSourceFactory.init((javax.sql.DataSource) getServletContext().getAttribute(org.apache.struts.Globals.DATA_SOURCE_KEY), this.logger);
      for (int i = 1;; i++) {
        javax.sql.DataSource extDataSource = (javax.sql.DataSource) getServletContext().getAttribute(
            GlobalConstant.EXTERNAL_DATA_SOURCE + i);
        if (extDataSource == null) {
          break;
	}
        logger.info("Initialize External Datasource:" + GlobalConstant.EXTERNAL_DATA_SOURCE + i);
        DataSourceFactory.initExternalDataSource(GlobalConstant.EXTERNAL_DATA_SOURCE + i, extDataSource);
      }
    } catch (Exception e) {
      logger.error("MainActionServlet.initDataSource() failed", e);
      throw new javax.servlet.ServletException(e);
    }
    logger.info("MainActionServlet.initDataSource() finished");
  }

	/**
   * startFullTextIndexFactory
   * 
   * @throws javax.servlet.ServletException
   */
  protected void startFullTextIndexFactory() throws javax.servlet.ServletException {
    logger.info("MainActionServlet.initFullTextIndexFactory() start");
    try {
      IndexAutoTrigger.startIndexTask();
    } catch (Exception e) {
      logger.error("MainActionServlet.initFullTextIndexFactory() failed", e);
      throw new javax.servlet.ServletException(e);
    }
    logger.info("MainActionServlet.initFullTextIndexFactory() finished");
  }

  /**
   * initMessageResources
   * 
   * @throws javax.servlet.ServletException
   */
  protected void initMessageResources() throws javax.servlet.ServletException {
    logger.info("MainActionServlet.initMessageResources() start");
    try {
      MessageResourcesFactory.init((org.apache.struts.util.MessageResources) getServletContext().getAttribute(
          org.apache.struts.Globals.MESSAGES_KEY), (org.apache.struts.util.MessageResources) getServletContext().getAttribute("customize"));
    } catch (Exception e) {
      logger.error("MainActionServlet.initMessageResources() failed", e);
      throw new javax.servlet.ServletException(e);
    }
    logger.info("MainActionServlet.initMessageResources() finished");
  }

  /**
	 * initGlobalReference
	 * 
	 * @throws javax.servlet.ServletException
	 */
  protected void initGlobalReference() throws javax.servlet.ServletException {
    logger.info("MainActionServlet.initGlobalReference() start");
		java.sql.Connection conn = null;

		try {
			conn = DataSourceFactory.getConnection();
			GlobalReferenceDAObject gloRefDAO = new GlobalReferenceDAObject(conn);

			// Initialize system parameters hash table.
			Hashtable sysParaHash = gloRefDAO.getAllSysParameter();

			// Override the database system parameters configuration with property
			// file
      sysParaHash.putAll(Utility.parseResourceBundle(GlobalConstant.CONFIG_FILENAME));
			SystemParameterFactory.init(sysParaHash);

			// Initialize user names and user emails hash tables.
			Hashtable userInfoHash = gloRefDAO.getAllUserInfo();
			UserInfoFactory.init(userInfoHash);

			gloRefDAO = null;
		} catch (Exception e) {
      logger.error("MainActionServlet.initGlobalReference() failed", e);
			throw new javax.servlet.ServletException(e);
		} finally {
			try {
				conn.close();
			} catch (Exception ignore) {
			} finally {
				conn = null;
			}
		}
    logger.info("MainActionServlet.initGlobalReference() finished");
	}

  /**
   * loadEventCode
   * 
   * @throws javax.servlet.ServletException
   */
  protected void loadEventCode() {
    logger.info("MainActionServlet.loadEventCode start");
		java.sql.Connection conn = null;
		Hashtable eventCodehash = new Hashtable();

    if (TextUtility.parseInteger(SystemParameterFactory.getSystemParameter(SystemParameterConstant.SYSTEMLOG_EVENTLOG)) > 0) {
			try {
				conn = DataSourceFactory.getConnection();
				SessionContainer sessionContainer = new SessionContainer();
        EventMessageCodeDAObject eventCodeDAO = new EventMessageCodeDAObject(sessionContainer, conn);
				List eventCodeList = eventCodeDAO.getList();
				int len = eventCodeList.size();

				for (int i = 0; i < len; i++) {
					EventMessageCode eventCode = (EventMessageCode) eventCodeList.get(i);
					String type = eventCode.getEventType();
          int systemType = TextUtility.parseInteger(SystemParameterFactory.getSystemParameter(SystemParameterConstant.SYSTEMLOG_EVENTLOG));
					if (systemType > 0) {
						if (systemType == 3
                && (EventLogger.EVENT_TYPE_ERROE.equals(type) || EventLogger.EVENT_TYPE_WARNING.equals(type) || EventLogger.EVENT_TYPE_INFO
										.equals(type))) {
							String msgCode = eventCode.getMsgCode();
							String eventType = eventCode.getEventType();
							eventCodehash.put(msgCode, eventType);
            } else if (systemType == 2 && (EventLogger.EVENT_TYPE_WARNING.equals(type) || EventLogger.EVENT_TYPE_ERROE.equals(type))) {
							String msgCode = eventCode.getMsgCode();
							String eventType = eventCode.getEventType();
							eventCodehash.put(msgCode, eventType);
            } else if (systemType == 1 && (EventLogger.EVENT_TYPE_ERROE.equals(type))) {
							String msgCode = eventCode.getMsgCode();
							String eventType = eventCode.getEventType();
							eventCodehash.put(msgCode, eventType);
						}
					}
				}
			} catch (Exception e) {
        logger.error(e, e);
			} finally {
				try {
					conn.close();
				} catch (Exception ignore) {
				} finally {
					conn = null;
				}
			}
		}

    this.getServletContext().setAttribute(GlobalConstant.EVENT_CODE_KEY, eventCodehash);
    logger.info("MainActionServlet.loadEventCode() finished");
	}

  /**
   * resetLoginLog
   * 
   * @throws javax.servlet.ServletException
   */
  protected void resetLoginLog() throws ServletException {
    logger.info("MainActionServlet.resetLoginLog() start");
		Connection conn = null;
		try {
			conn = DataSourceFactory.getConnection();
			SessionContainer sessionContainer = new SessionContainer();
      AuditLoginOutDAObject auditLoginOutDAObject = new AuditLoginOutDAObject(sessionContainer, conn);
			auditLoginOutDAObject.resetLoginLog();
			conn.commit();
		} catch (Exception e) {
      logger.info("MainActionServlet.resetLoginLog() fail");
      throw new javax.servlet.ServletException(e);
		} finally {
			try {
				conn.close();
			} catch (Exception ignore) {
			} finally {
				conn = null;
			}
		}
    logger.info("MainActionServlet.resetLoginLog() finished");
	}

  /**
   * initScheduler
   * 
   * @throws javax.servlet.ServletException
   */
  protected void initScheduler() throws javax.servlet.ServletException {
    logger.info("MainActionServlet.initScheduler() start");

    String sDSName = SystemParameterFactory.getSystemParameter(SystemParameterConstant.SCHEDULER_JOBSTORE_DATASOURCE);
    Map mapDS = ((ModuleConfig) getServletContext().getAttribute(org.apache.struts.Globals.MODULE_KEY)).findDataSourceConfig(
        "org.apache.struts.action.DATA_SOURCE").getProperties();

    Properties properties = new Properties();
    properties.setProperty("org.quartz.scheduler.instanceName", SystemParameterFactory
        .getSystemParameter(SystemParameterConstant.SCHEDULER_INSTANCE_NAME));
    properties.setProperty("org.quartz.scheduler.instanceId", SystemParameterFactory
        .getSystemParameter(SystemParameterConstant.SCHEDULER_INSTANCE_ID));
    properties.setProperty("org.quartz.scheduler.rmi.export", SystemParameterFactory
        .getSystemParameter(SystemParameterConstant.SCHEDULER_RMI_EXPORT));
    properties.setProperty("org.quartz.scheduler.rmi.proxy", SystemParameterFactory
        .getSystemParameter(SystemParameterConstant.SCHEDULER_RMI_PROXY));

    properties.setProperty("org.quartz.threadPool.class", SystemParameterFactory
        .getSystemParameter(SystemParameterConstant.SCHEDULER_THREADPOOL_CLASS));
    properties.setProperty("org.quartz.threadPool.threadCount", SystemParameterFactory
        .getSystemParameter(SystemParameterConstant.SCHEDULER_THREADPOOL_COUNT));
    properties.setProperty("org.quartz.threadPool.threadPriority", SystemParameterFactory
        .getSystemParameter(SystemParameterConstant.SCHEDULER_THREADPOOL_PRIORITY));

    properties.setProperty("org.quartz.jobStore.class", SystemParameterFactory
        .getSystemParameter(SystemParameterConstant.SCHEDULER_JOBSTORE_CLASS));

    if (DataSourceFactory.getDatabaseType() == DataSourceFactory.DB_MSSQL) {
      properties.setProperty("org.quartz.jobStore.driverDelegateClass", "org.quartz.impl.jdbcjobstore.MSSQLDelegate");
    } else if (DataSourceFactory.getDatabaseType() == DataSourceFactory.DB_ORACLE) {
      properties.setProperty("org.quartz.jobStore.driverDelegateClass", "org.quartz.impl.jdbcjobstore.oracle.OracleDelegate");
    } else {
      properties.setProperty("org.quartz.jobStore.driverDelegateClass", SystemParameterFactory
          .getSystemParameter(SystemParameterConstant.SCHEDULER_JOBSTORE_DRIVERDELEGATECLASS));
    }

    properties.setProperty("org.quartz.jobStore.dataSource", sDSName);
    properties.setProperty("org.quartz.jobStore.tablePrefix", SystemParameterFactory
        .getSystemParameter(SystemParameterConstant.SCHEDULER_JOBSTORE_TABLEPREFIX));
    properties.setProperty("org.quartz.jobStore.instanceId", SystemParameterFactory
        .getSystemParameter(SystemParameterConstant.SCHEDULER_JOBSTORE_INSTANCEID));

    properties.setProperty("org.quartz.dataSource." + sDSName + ".driver", (String) mapDS.get("driverClassName"));
    properties.setProperty("org.quartz.dataSource." + sDSName + ".URL", (String) mapDS.get("url"));
    properties.setProperty("org.quartz.dataSource." + sDSName + ".user", (String) mapDS.get("username"));
    properties.setProperty("org.quartz.dataSource." + sDSName + ".password", (String) mapDS.get("password"));
    properties.setProperty("org.quartz.dataSource." + sDSName + ".maxConnections", SystemParameterFactory
        .getSystemParameter(SystemParameterConstant.SCHEDULER_JOBSTORE_DB_POOL_SIZE));
    properties.setProperty("org.quartz.dataSource." + sDSName + ".minConnections", "1");

    try {
      Scheduler scheduler = new StdSchedulerFactory(properties).getScheduler();

      // Add job listener for all of auto tasks.
      // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      scheduler.addJobListener(new JobListener() {

        public String getName() {
          return (AutomaticTaskHandler.AUTOMATIC_TASK_LISTENER_EKY);
        }

        public void jobExecutionVetoed(JobExecutionContext context) {
        }

        public void jobToBeExecuted(JobExecutionContext context) {

          Scheduler jobScheduler = context.getScheduler();
          JobDetail jobDetail = context.getJobDetail();
          JobDataMap jobDataMap = jobDetail.getJobDataMap();

          logger.info("Job " + jobDetail.getFullName() + "is starting to execute.");

          if (!jobDataMap.containsKey(AutomaticTaskHandler.AUTOMATIC_TASK_STATE_KEY)) {
            jobDataMap.put(AutomaticTaskHandler.AUTOMATIC_TASK_STATE_KEY, GlobalConstant.FALSE);
            return;
          }

          String executStat = jobDataMap.getString(AutomaticTaskHandler.AUTOMATIC_TASK_STATE_KEY);

          if (GlobalConstant.TRUE.equals(executStat)) { // If current job have completed, try to unschedule.
            try {
              logger.info("Try to unschedule auto job: " + jobDetail.getFullName());
              jobScheduler.unscheduleJob(jobDetail.getName(), jobDetail.getGroup());
              logger.info("Unschedule job: " + jobDetail.getFullName() + " success.");
            } catch (SchedulerException se) { // If exception occur, nothing to do and try to unschedule this job next
                                              // fire.
              logger.error("Error occur at unschedule auto job!" + se);
            }
          }
        }

        public void jobWasExecuted(JobExecutionContext context, JobExecutionException jobException) {
        }

      });

      com.dcivision.framework.SchedulerFactory.init(scheduler);
      com.dcivision.framework.SchedulerFactory.getScheduler().start();
    } catch (SchedulerException e) {
      logger.error("MainActionServlet.initScheduler() failed", e);
      throw new javax.servlet.ServletException(e);
    }
    logger.info("MainActionServlet.initScheduler() finished");
  }

  /**
   * initSysFunction
   * 
   * @throws ServletException
   */
  protected void initSysFunction(ApplicationContainer appContainer) throws javax.servlet.ServletException {
    logger.info("MainActionServlet.initSysFunction() start");
    java.sql.Connection conn = null;

    try {
      conn = DataSourceFactory.getConnection();
      SysFunctionDAObject sysFunctionDAO = new SysFunctionDAObject(null, conn);

      // get all activated system function
      List lSysFunction = sysFunctionDAO.getFullList();
      appContainer.setSysFunctionList(lSysFunction);

		} catch (Exception e) {
      logger.error("MainActionServlet.initSysFunction() failed", e);
      throw new javax.servlet.ServletException(e);
    } finally {
      try {
        conn.close();
      } catch (Exception ignore) {
      } finally {
        conn = null;
		}
	}
    logger.info("MainActionServlet.initSysFunction() finished");
  }

  /**
   * initDmsProfileJob
   * 
   * @throws ServletException
   */
  protected void initDmsProfileJob() throws javax.servlet.ServletException {
    logger.info("MainActionServlet.initDmsProfileJob() start");
    org.quartz.Scheduler sched = com.dcivision.framework.SchedulerFactory.getScheduler();
    try {
      if (sched.getJobDetail("PROFILE_JOB", "PROFILR_JOBGROUP") == null) {
        JobDetail jobDetail = new JobDetail("PROFILE_JOB", "PROFILR_JOBGROUP", DmsProfileJob.class);

        String viewPath = this.getServletContext().getRealPath("viewer");
        jobDetail.getJobDataMap().put("viewPath", viewPath);

        CronTrigger cornTrigger = new CronTrigger("PROFILE_TRIGGER", "PEOFILE_TRIGGERGROUP");
        // cornTrigger.setCronExpression("0 0 0 1/1 * ?");
        // cornTrigger.setCronExpression("0 * * * * ?");
        // EIP-1405 diff from clear-cache-file job which default start at 00:00
        cornTrigger.setCronExpression("0 0 1 ? * *");
        sched.scheduleJob(jobDetail, cornTrigger);
  	}
    } catch (SchedulerException e) {
      logger.info("MainActionServlet.initDmsProfileJob() failed", e);
      throw new javax.servlet.ServletException(e);
    } catch (ParseException e) {
      logger.info("MainActionServlet.initDmsProfileJob() failed", e);
      throw new javax.servlet.ServletException(e);
    }
    logger.info("MainActionServlet.initDmsProfileJob() finished");
  }
  	
  /**
   * Set clear cache job to schedular Copy from MainActionServlet initClearCacheFile
   * 
   * @throws javax.servlet.ServletException
   */
  protected void initClearCacheFileJob() throws javax.servlet.ServletException {
    logger.info("MainActionServlet.initClearCacheFileJob() start");
    String tmpTriggerTime = SystemParameterFactory
        .getSystemParameter(com.dcivision.framework.SystemParameterConstant.DMS_CLEAR_CACHE_FILE_TRIGGER_TIME);
  	
    if (!Utility.isEmpty(tmpTriggerTime)) {
  	int triggerHours = 0;
  	int triggerMinutes = 0;
  	int triggersecond = 0;
  	StringTokenizer timeToken = new StringTokenizer(tmpTriggerTime,":");
  	
  	int i = 0;
  	while (timeToken.hasMoreTokens()){
  		++i;
  		if (i == 1) {
  			triggerHours = TextUtility.parseInteger(timeToken.nextToken());
  		}
  		if (i == 2) {
  			triggerMinutes = TextUtility.parseInteger(timeToken.nextToken());
  		}
  		if (i == 3) {
  			triggersecond = TextUtility.parseInteger(timeToken.nextToken());   
  		}
  	}
  	
      String triggerExpression = triggersecond + " " + triggerMinutes + " " + triggerHours + " ? * *";
      org.quartz.Scheduler sched = com.dcivision.framework.SchedulerFactory.getScheduler();
      try {
        String jobName = GlobalConstant.JOB_PREFIX_DMS_CLEAR_CACHE + "JOB";
        String jobGroup = GlobalConstant.JOB_PREFIX_DMS_CLEAR_CACHE + "JOBGROUP";
        if (sched.getJobDetail(jobName, jobGroup) == null) {
          String triggerName = GlobalConstant.JOB_PREFIX_DMS_CLEAR_CACHE + "TRIGGER";
          String triggerGroup = GlobalConstant.JOB_PREFIX_DMS_CLEAR_CACHE + "TRIGGERGROUP";

          JobDetail jobDetail = new JobDetail(jobName, jobGroup, DmsDocumentClearCache.class);
          CronTrigger cornTrigger = new CronTrigger(triggerName, triggerGroup);
          cornTrigger.setCronExpression(triggerExpression);
          sched.scheduleJob(jobDetail, cornTrigger);
  	}
      } catch (SchedulerException e) {
        logger.error("MainActionServlet.initClearCacheFileJob() failed", e);
        throw new javax.servlet.ServletException(e);
      } catch (ParseException e) {
        logger.error("MainActionServlet.initClearCacheFileJob() failed", e);
        throw new javax.servlet.ServletException(e);
      }
    }
    logger.info("MainActionServlet.initClearCacheFileJob() finished");
  }
  	
  /**
   * Set EmailSolution job to schedular
   */
  protected void startEmailArchiveTracker() throws javax.servlet.ServletException {
    logger.info("MainActionServlet.startEmailArchiveTracker() start");
  	try {
      EmailSolutionHandler emailSolutionHandler = new EmailSolutionHandler();
      emailSolutionHandler.setEmailSolutionHandlerScheduleJob();
    } catch (Exception e) {
      logger.error("MainActionServlet.startEmailArchiveTracker() failed", e);
      throw new javax.servlet.ServletException(e);
		}
    logger.info("MainActionServlet.startEmailArchiveTracker() finished");
  }
}